/**
 * This code checks to see if a Java Virtual Machine respects important 
 * properties of volatile variables.
 *
 * This particular test ensures that reads and writes of volatile longs 
 * are performed atomically.  
 *
 * The bad compiler optimization mentioned below indicates a bug in the 
 * handling of operations on long integers.  This should not be a problem 
 * on most platforms.
 * 
 * The other test is a little more peculiar.  Writes to 64-bit (long)
 * volatiles must be performed atomically.  Each thread has a "key", 
 * a 64 bit number whose rightmost 32 bits are identical to its leftmost
 * 32 bits.  Each thread repeatedly writes its key to a shared volatile long.
 * This write should be performed atomically: all 64 bits should be from the 
 * same write.  This means that, when read, the volatile long's rightmost 
 * 32 bits should always be identical to its leftmost 32 bits.
 *
 * Each thread repeatedly reads this value.   If the 32 rightmost bits are 
 * not the same as the 32 leftmost bits at some point, then either the read
 * that obtained that value was not atomic, or the write that wrote that 
 * value was not atomic.
 *
 * Because two threads are involved in this mistake, the error message may 
 * get printed twice before the system has a chance to exit.
 *
 * There are two command line arguments allowed.  The first is the number 
 * of threads, and the second is the number of iterations each thread will 
 * go through to find non-atomic longs.
 */

public class AtomicLong extends Thread {
    static volatile long v;
    static int w;
    static volatile long v2;
    static int count = 10000000;
    
    long key;

    AtomicLong(int k) {
	long temp = k;
	key = (temp<< 32) | temp;
    }

    public void check(long temp) {
	    long temp1 = temp>>>32;
	    long temp2 = (temp <<32) >>>32;
	    long temp3 = 0xffffffffL & temp;

	    if (temp2 != temp3) {
		System.out.println("Bad compiler optimization.\n\n" +
				   "There is a bug in the handling of longs " +
				   " in this VM.\n" +
				   Long.toHexString(temp)
				   +" botton 32 bits are either " + Long.toHexString(temp2)
				   + " or " + Long.toHexString(temp3));
		System.exit(1);
	    }
	    if (temp1 != temp3) {
		System.out.println("Nonatomic write to or read from a volatile long.\n\n" +
				   "This means that one of two things happened.\n" +
				   "1) Two threads may have written to a volatile " +
				   "variable in such a way that\none wrote the first 32 bits, " +
				   "and the other wrote the second 32 bits.\n" + 
				   "2) A thread reading the volatile might have read " +
				   "the first 32 bits from one\nwrite and the second 32 bits " + 
				   "from another.\n\nEither way, it is a violation of the " + 
				   "semantics of volatile variables.\n" +
				   "Saw " + Long.toHexString(temp)
				   +" which is " + Long.toHexString(temp1)
				   + "." + Long.toHexString(temp2));
		System.exit(1);
	    }
    }

    public void run() {
	for(int i = 0; i < count; i++) {
	    check(v);
	    v = key;
	    check(v2);
	    v = key;
	    }
    }





    public static void main(String args[]) {
	int threads = 10;
	if (args.length > 0) {
	    threads = Integer.parseInt(args[0]);
	    if (args.length > 1) 
		count = Integer.parseInt(args[1]);
	}
	if (threads > (1L << 32)) {
	    System.err.println("Too many threads.");
	    System.exit(1);
	}
	for(int t = 1; t < threads; t++) 
	    new AtomicLong(t).start();
    }
}